cmake_minimum_required(VERSION 2.8.5)

if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
	# If this is the root project, issue a project() command so that
	# the Visual Studio generator will create an .sln file.
    set(CMAKE_CONFIGURATION_TYPES "Debug;RelWithAsserts;RelWithDebInfo" CACHE INTERNAL "Build configs")
	project(Junction)
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
    set(JUNCTION_WITH_SAMPLES TRUE CACHE BOOL "Include all Junction samples in generated build system")
    set(JUNCTION_MAKE_INSTALLABLE TRUE)
    set(TURF_MAKE_INSTALLABLE TRUE)
endif()	

# Default values, can be overridden by user
set(JUNCTION_USERCONFIG "" CACHE STRING "Optional path to additional config file (relative to root CMakeLists.txt)")
set(JUNCTION_WITH_FOLLY FALSE CACHE BOOL "Use Folly")
set(JUNCTION_WITH_CDS FALSE CACHE BOOL "Use CDS")
set(JUNCTION_WITH_NBDS FALSE CACHE BOOL "Use NBDS")
set(JUNCTION_WITH_TBB FALSE CACHE BOOL "Use TBB")
set(JUNCTION_WITH_TERVEL FALSE CACHE BOOL "Use Tervel")
set(JUNCTION_TRACK_GRAMPA_STATS FALSE CACHE BOOL "Enable stats in ConcurrentMap_Grampa")
set(JUNCTION_USE_STRIPING TRUE CACHE BOOL "Allocate a fixed-size ConditionBank for striped primitives")

# Initialize variables used to collect include dirs/libraries.
set(JUNCTION_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/include")
set(JUNCTION_ALL_INCLUDE_DIRS "${JUNCTION_INCLUDE_DIRS}")
set(JUNCTION_ALL_LIBRARIES junction)
set(JUNCTION_ALL_DLLS "")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

# Add turf targets and import its macros since we use them below
get_filename_component(outerPath "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
set(TURF_ROOT "${outerPath}/turf" CACHE STRING "Path to Turf")
include("${TURF_ROOT}/cmake/Macros.cmake")
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
    # If this is the root project, apply build settings here so that
    # they're applied to all targets
    ApplyTurfBuildSettings()
endif()
add_subdirectory(${TURF_ROOT} turf)
list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${TURF_INCLUDE_DIRS})
list(APPEND JUNCTION_ALL_LIBRARIES ${TURF_ALL_LIBRARIES})

# Optional: Locate Folly and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_FOLLY)
	find_package(Folly REQUIRED)
	list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${FOLLY_INCLUDE_DIR})
	list(APPEND JUNCTION_ALL_LIBRARIES ${FOLLY_LIBRARIES})
endif()

# Optional: Locate CDS and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_CDS)
    find_package(CDS REQUIRED)
    list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${CDS_INCLUDE_DIR})
    list(APPEND JUNCTION_ALL_LIBRARIES ${CDS_LIBRARY})
    list(APPEND JUNCTION_ALL_DLLS ${CDS_DLL})
endif()

# Optional: Locate NBDS and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_NBDS)
    set(NBDS_USE_TURF_HEAP FALSE CACHE BOOL "Redirect NBDS's memory allocator to use Turf")
    find_package(NBDS REQUIRED)
    list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${NBDS_INCLUDE_DIRS})
    # If NBDS_USE_TURF_HEAP=1, then NBDS has dependencies on junction, so add junction to the linker
    # command line again as needed by the GNU linker.
    list(APPEND JUNCTION_ALL_LIBRARIES ${NBDS_LIBRARIES} junction)
endif()

# Optional: Locate Intel TBB and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_TBB)
    set(TBB_USE_TURF_HEAP FALSE CACHE BOOL "Redirect TBB's memory allocator to use Turf")
    find_package(TBB REQUIRED)
    list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${TBB_INCLUDE_DIRS})
    # If TBB_USE_TURF_HEAP=1, then TBB has dependencies on junction, so add junction to the linker
    # command line again as needed by the GNU linker.
    list(APPEND JUNCTION_ALL_LIBRARIES ${TBB_LIBRARIES} junction)
endif()

# Optional: Locate Tervel and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_TERVEL)
    find_package(Tervel REQUIRED)
    list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${TERVEL_INCLUDE_DIRS})
    list(APPEND JUNCTION_ALL_LIBRARIES ${TERVEL_LIBRARIES})
endif()

# Optional: Locate libcuckoo and append it to the list of include dirs/libraries.
if(JUNCTION_WITH_LIBCUCKOO)
    find_package(LibCuckoo REQUIRED)
    list(APPEND JUNCTION_ALL_INCLUDE_DIRS ${LIBCUCKOO_INCLUDE_DIRS})
endif()

# If this is the root listfile, add all samples
if((CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) AND JUNCTION_WITH_SAMPLES)
    file(GLOB children samples/*)
    foreach(child ${children})
        if(EXISTS "${child}/CMakeLists.txt")
            add_subdirectory("${child}")
        endif()
    endforeach()
endif()

# Gather source files.
GetFilesWithSourceGroups(GLOB_RECURSE JUNCTION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/junction junction/*.cpp junction/*.h)

# Configure autogenerated headers.
ConfigureFileIfChanged(cmake/junction_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/junction_config.h" JUNCTION_FILES)
if(JUNCTION_USERCONFIG)
    # Interpret JUNCTION_USERCONFIG relative to root project, in case Junction was added as a subdirectory
    GetAbsoluteRelativeTo(absPath "${CMAKE_SOURCE_DIR}" "${JUNCTION_USERCONFIG}")
    ConfigureFileIfChanged("${absPath}" "${CMAKE_CURRENT_BINARY_DIR}/include/junction_userconfig.h" JUNCTION_FILES)
else()
    WriteFileIfDifferent("// JUNCTION_USERCONFIG not set when CMake was run. This is a placeholder file.\n" "${CMAKE_CURRENT_BINARY_DIR}/include/junction_userconfig.h" JUNCTION_FILES)
endif()

# Define library target.
add_library(junction ${JUNCTION_FILES})

# Set include dirs for this library (done last, so it's not inherited by subprojects like Tervel, NBDS).
include_directories(${JUNCTION_ALL_INCLUDE_DIRS})

# Make installable.
if(JUNCTION_MAKE_INSTALLABLE)
    install(TARGETS junction DESTINATION lib)
    install(DIRECTORY junction/ DESTINATION include/junction FILES_MATCHING PATTERN "*.h")
    file(GLOB configHeaders "${CMAKE_CURRENT_BINARY_DIR}/include/*.h")
    install(FILES ${configHeaders} DESTINATION include)
endif()

# Export include dirs/libraries to parent project if we were invoked using add_subdirectory().
if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
    set(JUNCTION_INCLUDE_DIRS "${JUNCTION_INCLUDE_DIRS}" PARENT_SCOPE)
    set(JUNCTION_ALL_INCLUDE_DIRS "${JUNCTION_ALL_INCLUDE_DIRS}" PARENT_SCOPE)
    set(JUNCTION_ALL_LIBRARIES "${JUNCTION_ALL_LIBRARIES}" PARENT_SCOPE)
    set(JUNCTION_ALL_DLLS "${JUNCTION_ALL_DLLS}" PARENT_SCOPE)
endif()

